#pragma once

#include <cstdint>
#include "Core/Math/ScalarTypes.h"
#include "Core/Render/RenderStruct.h"

namespace SL
{

class RenderDevice;

enum class BackEndType : uint8_t
{
    NONE = 0,
    DirectX12 = 1,
    Vulkan = 2,
    Debug = 3,
};

enum class ExtensionType : uint8_t
{
    SWAPCHAIN,
    MESH_SHADER,
    RAY_TRACING,
    WORK_GRAPH
};

enum class FeatureLevel : uint32_t
{
    FEATURE_LEVEL_1_0_GENERIC = 0x100,
    FEATURE_LEVEL_1_0_CORE = 0x1000,
    FEATURE_LEVEL_9_1 = 0x9100,
    FEATURE_LEVEL_9_2 = 0x9200,
    FEATURE_LEVEL_9_3 = 0x9300,
    FEATURE_LEVEL_10_0 = 0xa000,
    FEATURE_LEVEL_10_1 = 0xa100,
    FEATURE_LEVEL_11_0 = 0xb000,
    FEATURE_LEVEL_11_1 = 0xb100,
    FEATURE_LEVEL_12_0 = 0xc000,
    FEATURE_LEVEL_12_1 = 0xc100,
    FEATURE_LEVEL_12_2 = 0xc200
};

struct Adapter
{
    wchar_t Description[128];
    // uint32 VendorId;
    // uint32 DeviceId;
    // uint32 SubSysId;
    // uint32 Revision;
    // uint64 DedicatedVideoMemory;
    // uint64 DedicatedSystemMemory;
    // uint64 SharedSystemMemory;
    // LUID AdapterLuid;
    uint32 index;
    FeatureLevel featureLevel;
};

/**
 * @brief
 * 1. enumerate adapters and capabilities
 *  swapchain support
 *  extentions
 *  determine adapters to use
 *
 * 2. provide debugging and profiling
 *
 * 3. create and destroy render devices
 */

class RenderBackend
{
public:
    virtual bool createInstance() = 0;
    virtual RenderDevice createDefaultRenderDevice() = 0;

    virtual std::vector<Adapter> enumerateAdapters() = 0;
    virtual RenderDevice createRenderDevice(Adapter) = 0;
    virtual bool destroyRenderDevice(RenderDevice device) = 0;

    virtual bool enableValidationLayer(RenderDevice device) = 0;

    bool debugEnabled() {return debug;}

protected:
    BackEndType getBackEndType() const { return backendType; }
    BackEndType backendType;
    bool debug;
};

} // namespace SL